package model

import (
	"context"
	"database/sql"
	"portal/internal/errorx"
	"portal/internal/tool"

	"github.com/Masterminds/squirrel"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
)

var _ SysMenuModel = (*customSysMenuModel)(nil)

type (
	// SysMenuModel is an interface to be customized, add more methods here,
	// and implement the added methods in customSysMenuModel.
	SysMenuModel interface {
		sysMenuModel
		withSession(session sqlx.Session) SysMenuModel
		InsertGetId(ctx context.Context, session sqlx.Session, data *SysMenu)(int64,error)
		GetListByRoleIds(ctx context.Context,session sqlx.Session,roleIds []*int64)([]*SysMenu,error)
		GetOprPermission(ctx context.Context,session sqlx.Session,perms string,roleIds []*int64)(*SysMenu,error)
		ExistByMIdRIds(ctx context.Context,session sqlx.Session,menuId int64,roleIds []*int64)(error)
		GetListByParentIds(ctx context.Context,session sqlx.Session,parentIds []*int64)([]*SysMenu,error)
		DeleteByIds(ctx context.Context,session sqlx.Session,menuIds []*int64)(error)
		Edit(ctx context.Context, session sqlx.Session, data *SysMenu)error
	}

	customSysMenuModel struct {
		*defaultSysMenuModel
	}
)

// NewSysMenuModel returns a model for the database table.
func NewSysMenuModel(conn sqlx.SqlConn) SysMenuModel {
	return &customSysMenuModel{
		defaultSysMenuModel: newSysMenuModel(conn),
	}
}

func (m *customSysMenuModel) withSession(session sqlx.Session) SysMenuModel {
	return NewSysMenuModel(sqlx.NewSqlConnFromSession(session))
}

func (m *customSysMenuModel)GetListByRoleIds(ctx context.Context,session sqlx.Session,roleIds []*int64)([]*SysMenu,error){
	sb := squirrel.Select("menu.*").Distinct().
			From("sys_role_menu rm")
	if roleIds != nil {
		sb = sb.Where(squirrel.Eq{"role_id":roleIds})
	}
	sb = sb.InnerJoin("sys_menu menu on menu.menu_id = rm.menu_id")
	query,args,err := sb.ToSql()
	if err != nil {
		return nil,err
	}
	var menus []*SysMenu
	if session != nil {
		err = session.QueryRowsPartialCtx(ctx,&menus,query,args...)
	}else{
		err = m.conn.QueryRowsPartialCtx(ctx,&menus,query,args...)
	}
	return menus,err
}


func (m *customSysMenuModel)GetOprPermission(ctx context.Context,session sqlx.Session,perms string,roleIds []*int64)(*SysMenu,error){
	sb := squirrel.Select("rm.*").From(m.table + " m").
		Where(squirrel.Eq{"m.perms":perms}).
		Where(squirrel.Eq{"m.menu_type":"F"})
	innerJoin := "sys_role_menu rm on rm.menu_id = m.menu_id and rm.role_id in (" + tool.TransArrInt64ToStr(roleIds) + ")"
	
	sb = sb.InnerJoin(innerJoin).Limit(1)
	query,args,err := sb.ToSql()
	if err != nil {
		return nil,err
	}
	var menu SysMenu
	if session != nil {
		err = session.QueryRowPartialCtx(ctx,&menu,query,args...)
	}else{
		err = m.conn.QueryRowPartialCtx(ctx,&menu,query,args...)
	}
	return &menu,err
}

func (m *customSysMenuModel)ExistByMIdRIds(ctx context.Context,session sqlx.Session,menuId int64,roleIds []*int64)(error){
	sb := squirrel.Select("1").From("sys_role_menu").
			Where(squirrel.Eq{"menu_id":menuId}).
			Where(squirrel.Eq{"role_id":roleIds}).
			Limit(1)
	query,args,err := sb.ToSql()
	if err != nil {
		return err
	}
	var count int64
	if session != nil {
		err = session.QueryRowPartialCtx(ctx, &count, query, args...)
	} else {
		err = m.conn.QueryRowPartialCtx(ctx, &count,query, args...)
	}
	if err != nil || count <= 0 {
		return errorx.SqlExistError
	}
	return nil
}

func (m *customSysMenuModel)GetListByParentIds(ctx context.Context,session sqlx.Session,parentIds []*int64)([]*SysMenu,error){
	sb := squirrel.Select("*").From(m.table).
			Where(squirrel.Eq{"parent_id":parentIds})
	query,args,err := sb.ToSql()
	if err != nil {
		return nil,err
	}
	var menus []*SysMenu
	if session != nil {
		err = session.QueryRowsPartialCtx(ctx,&menus,query,args...)
	}else{
		err = m.conn.QueryRowsPartialCtx(ctx,&menus,query,args...)
	}
	return menus,err
}

func (m *customSysMenuModel)DeleteByIds(ctx context.Context,session sqlx.Session,menuIds []*int64)(error){
	db := squirrel.Delete(m.table).
			Where(squirrel.Eq{"menu_id":menuIds})
	query,args,err := db.ToSql()
	if err != nil {
		return err
	}
	if session != nil {
		_,err = session.ExecCtx(ctx, query, args...)
	} else {
		_,err = m.conn.ExecCtx(ctx, query, args...)
	}
	return err
}

func (m *customSysMenuModel)InsertGetId(ctx context.Context, session sqlx.Session, data *SysMenu)(int64,error){
	query, args, err := squirrel.Insert(m.table).Columns(sysMenuInsertRows).
		Values(data.MenuName,data.ParentId,data.OrderNum,data.Path,data.Component,data.Query,data.IsFrame,data.IsCache,data.MenuType,data.Visible,data.Status,data.Perms,data.Icon,data.CreateBy,data.CreateTime,data.UpdateBy,data.UpdateTime,data.Remark).
		ToSql()
	if err != nil {
		return 0, err
	}
	var sqlRes sql.Result
	if session != nil {
		sqlRes,err = session.ExecCtx(ctx, query, args...)
	} else {
		sqlRes,err = m.conn.ExecCtx(ctx, query, args...)
	}
	if err != nil {
		return 0, err
	}
	id,err := sqlRes.LastInsertId()
	return id, err
}

func (m *customSysMenuModel)Edit(ctx context.Context, session sqlx.Session, data *SysMenu)error{	
	
	query,args,err := squirrel.Update(m.table).
		SetMap(
			squirrel.Eq{
				"menu_name":data.MenuName,
				"menu_type":data.MenuType,
				"parent_id":data.ParentId,
				"order_num":data.OrderNum,
				"path":data.Path,
				"component":data.Component,
				"query":data.Query,
				"is_frame":data.IsFrame,
				"is_cache":data.IsCache,
				"visible":data.Visible,
				"status":data.Status,
				"perms":data.Perms,
				"icon":data.Icon,
				"update_time":data.UpdateTime,
				"update_by":data.UpdateBy,
			}).
		Where(squirrel.Eq{"menu_id":data.MenuId}).
		ToSql()
	if err != nil {
		return err
	}
	if session != nil {
		_,err = session.ExecCtx(ctx, query, args...)
	} else {
		_,err = m.conn.ExecCtx(ctx, query, args...)
	}
	return err
}